﻿using System;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web.Http;
using System.Web.Http.Controllers;
using Common.Logging;
using In.Api.Dto.HisWs;
using Newtonsoft.Json;
using OutDbContext;
using Rmq.Center;
using Senparc.Weixin.MP.TenPayLib;
using User.Api.BizExtensions;
using User.Api.Dto.Reg;
using User.Api.Helpers;
using User.Api.HttpClients;
using System.Collections.Generic;
using System.Data.Entity.SqlServer;
using System.Data.SqlClient;

namespace User.Api.Controllers
{


    public class RegController : ApiController
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(RegController));

        private static readonly object OrderNoLocker = new object();
        private static readonly object PayNotifyLocker = new object();
        private static TenPayInfo _tenPayInfo;

        public static TenPayInfo TenPayInfo
        {
            get
            {
                if (_tenPayInfo == null)
                {
                    _tenPayInfo =
                        TenPayInfoCollection.Data[ConfigurationManager.AppSettings["WeixinPay_PartnerId"]];
                }
                return _tenPayInfo;
            }
        }

        /// <summary>
        /// 生成预约订单，包含预约操作
        /// </summary>
        /// <param name="cardId">就诊卡id</param>
        /// <param name="deptId">科室院内编号</param>
        /// <param name="deptName">科室名称</param>
        /// <param name="doctorId">医生院内编号</param>
        /// <param name="doctorName">医生名称</param>
        /// <param name="regDate">挂号日期</param>
        /// <param name="timeSlice">排班时段</param>
        /// <param name="startTime">分时开始时间</param>
        /// <param name="endTime">分时结束时间</param>
        /// <param name="regType">号源类型</param>
        /// <param name="sqno">分时序号</param>
        /// <param name="fee">费用</param>
        /// <param name="treatFee">治疗费用</param>
        /// <param name="otherFee">其他分i鄂永</param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("CreateApptOrder")]
        public CreateApptOrderResponse CreateApptOrder(int cardId, string deptId, string deptName,
            string doctorId, string doctorName, string regDate, string timeSlice, string startTime,
            string endTime, string regType, string sqno, string fee, string treatFee, string otherFee)
        {
            var azUser = AzUser.GetInApi(Request);
            Card card;
            string openid;
            ApptOrder order;
            using (var _ctx = new HzfyWeiXinEntities())
            {
                card = _ctx.HospCard.Where(x => x.Id == cardId && x.WxUserId == azUser.UserId)
                    .Select(x => new Card
                    {
                        CardNo = x.CardNo,
                        Birthdate = x.Birthdate,
                        CardType = x.CardType,
                        PatientName = x.PatientName
                    }).FirstOrDefault();
                if (card == null)
                {
                    return new CreateApptOrderResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "找不到就诊卡信息"
                    };
                }

                var sameOrder = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .FirstOrDefault(x =>
                        x.CardNo == card.CardNo
                        && x.RegDate == regDate
                        );
                if (sameOrder != null)
                {
                    return new CreateApptOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "此卡号当天已有预约信息，不能再预约。一个卡号每天只能预约一个医生，一个预约时段！"
                    };
                }


                var cardSameDayAppointMax = ConfigurationManager.AppSettings["CardSameDayAppointMax"].ToInt32();
                var cardApptCount = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .Count(x => x.CardNo == card.CardNo && x.RegDate == regDate);
                if (cardApptCount >= cardSameDayAppointMax)
                {
                    return new CreateApptOrderResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "同一天最多可以预约挂号" + cardSameDayAppointMax + "次!"
                    };
                }

                var userobj = _ctx.WxUser.FirstOrDefault(x => x.Id == azUser.UserId);
                openid = userobj == null ? "" : userobj.OpenId;

                var orderNo = GenerateNewOrderNo();
                //新建订单
                order = new ApptOrder
                {
                    WxUserId = azUser.UserId,
                    OrderType = ApptOrderExtensions.OrderType.预约.ToInt32().ToString(), //微信预约订单
                    CardType = card.CardType.ToString(),
                    CardNo = card.CardNo,
                    DeptId = deptId,
                    DeptName = deptName,
                    DoctorId = doctorId,
                    DoctorName = doctorName,
                    OrderNo = orderNo,
                    RegDate = regDate,
                    OrderStatus = ApptOrderExtensions.OrderStatus.未锁号.ToInt32(), //新订单，未锁号（0）
                    TimeSlice = timeSlice,
                    StartTime = startTime,
                    EndTime = endTime,
                    RegType = regType,
                    PayState = ApptOrderExtensions.PayState.未付款.ToInt32().ToString(), //未支付
                    Fee = fee.ToDecimalOrDefault(),
                    TreatFee = treatFee.ToDecimalOrDefault(),
                    OtherFee = otherFee.ToDecimalOrDefault(),
                    SumFee = fee.ToDecimalOrDefault() + treatFee.ToDecimalOrDefault() + otherFee.ToDecimalOrDefault(),
                    CreateTime = DateTime.Now,
                    Sqno = sqno,
                    CardName = card.PatientName
                };

                _ctx.ApptOrder.Add(order);
                _ctx.SaveChanges();

                order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号中.ToInt32();
                _ctx.SaveChanges();
            }

            //执行锁号操作
            var lockRequest = new Request4ExeLockSource();
            lockRequest.OrderId = order.OrderNo;
            lockRequest.DeptId = order.DeptId;
            lockRequest.DoctorId = order.DoctorId;
            lockRequest.RegDate = order.RegDate;
            lockRequest.TimeSlice = order.TimeSlice;
            lockRequest.RegType = order.RegType;
            lockRequest.StartTime = order.StartTime;
            lockRequest.EndTime = order.EndTime;
            lockRequest.RegFee = order.Fee.GetValueOrDefault().ToString();
            lockRequest.TreatFee = order.TreatFee.GetValueOrDefault().ToString();
            lockRequest.OtherFee = order.OtherFee.GetValueOrDefault().ToString();
            //lockRequest.SumFee = order.SumFee.GetValueOrDefault().ToString();
            //lockRequest.SqNo = order.Sqno;

            Response4ExeLockSource lockResponse;

            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisNewWs/ExeLockSource", lockRequest).Result;
                responseMsg.EnsureSuccessStatusCode();
                lockResponse = responseMsg.Content.ReadAsAsync<Response4ExeLockSource>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内锁号Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号失败.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }


                return new CreateApptOrderResponse
                {
                    ResultCode = "7",
                    ResultMsg = "执行锁号操作超时"
                };
            }

            if (lockResponse.ResultCode != "0")
            {
                //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号失败.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }

                return new CreateApptOrderResponse
                {
                    ResultCode = "8",
                    ResultMsg = lockResponse.ResultDesc
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号成功.ToInt32();
            //order.LockTime = DateTime.Now;
            //_ctx.SaveChanges();

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.预约中.ToInt32();
            //_ctx.SaveChanges();
            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号成功.ToInt32()),
                    new SqlParameter("@LockTime", DateTime.Now),
                    new SqlParameter("@OrderId", order.Id),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus,LockTime = @LockTime where Id=@OrderId", para);

                para = new SqlParameter[]
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.预约中.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            }
            #region 不需要
            //// 执行预约操作
            //var apptRequest = new Request4ExeAppoint();
            //apptRequest.OrderId = order.OrderNo;
            //apptRequest.CardNo = order.CardNo;


            //Response4ExeAppoint apptResponse;
            //try
            //{
            //    var httpClient = InHttpClient.GetClient();
            //    var responseMsg = httpClient.PostAsJsonAsync("HisNewWs/ExeAppoint", apptRequest).Result;
            //    responseMsg.EnsureSuccessStatusCode();
            //    apptResponse = responseMsg.Content.ReadAsAsync<Response4ExeAppoint>().Result;
            //}
            //catch (Exception ex)
            //{
            //    Logger.ErrorFormat("调用院内预约Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

            //    //order.OrderStatus = ApptOrderExtensions.OrderStatus.预约失败.ToInt32();
            //    //_ctx.SaveChanges();
            //    using (var _ctx = new HzfyWeiXinEntities())
            //    {
            //        SqlParameter[] para =
            //            {
            //        new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.预约失败.ToInt32()),
            //        new SqlParameter("@OrderId", order.Id),
            //         };
            //        _ctx.Database.ExecuteSqlCommand(
            //            "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            //    }


            //    // RMQ 取消锁号
            //    var unlockingProducer = new OrderUnlockingProducer();
            //    unlockingProducer.Publish(new OrderUnlockingMsg
            //    {
            //        OrderType = OrderType.挂号订单,
            //        OrderId = order.Id
            //    });

            //    return new CreateApptOrderResponse
            //    {
            //        ResultCode = "9",
            //        ResultMsg = "执行预约操作超时"
            //    };
            //}

            //if (apptResponse.ResultCode != "0")
            //{
            //    //order.OrderStatus = ApptOrderExtensions.OrderStatus.预约失败.ToInt32();
            //    //_ctx.SaveChanges();
            //    using (var _ctx = new HzfyWeiXinEntities())
            //    {
            //        SqlParameter[] para =
            //            {
            //        new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.预约失败.ToInt32()),
            //        new SqlParameter("@OrderId", order.Id),
            //         };
            //        _ctx.Database.ExecuteSqlCommand(
            //            "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            //    }

            //    // RMQ 取消锁号
            //    var unlockingProducer = new OrderUnlockingProducer();
            //    unlockingProducer.Publish(new OrderUnlockingMsg
            //    {
            //        OrderType = OrderType.挂号订单,
            //        OrderId = order.Id
            //    });

            //    return new CreateApptOrderResponse
            //    {
            //        ResultCode = "10",
            //        ResultMsg = apptResponse.ResultDesc
            //    };
            //}

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.预约成功.ToInt32();
            //order.ApptTime = DateTime.Now;
            //_ctx.SaveChanges();
            #endregion
            using (var _ctx = new HzfyWeiXinEntities())
            {

                SqlParameter[] para = new SqlParameter[]
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.预约成功.ToInt32()),
                    new SqlParameter("@ApptTime", DateTime.Now),
                    new SqlParameter("@OrderId", order.Id)
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus,ApptTime = @ApptTime where Id=@OrderId", para);
            }

            // 费用为0的直接设置为支付成功
            if (order.SumFee == 0)
            {
                //order.PayState = ApptOrderExtensions.PayState.已付款.ToInt32().ToString();
                //order.PayTime = DateTime.Now;
                //order.WxTransactionId = "0";
                //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付成功.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para = new SqlParameter[]
                    {
                        new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付成功.ToInt32()),
                        new SqlParameter("@WxTransactionId", "0"),
                        new SqlParameter("@PayTime", DateTime.Now),
                        new SqlParameter("@PayState", ApptOrderExtensions.PayState.已付款.ToInt32().ToString()),
                        new SqlParameter("@OrderId", order.Id)
                    };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus,PayTime = @PayTime,PayState=@PayState, " +
                        "WxTransactionId=@WxTransactionId where Id=@OrderId", para);
                }

                // RMQ 执行取号
                var pickupingProducer = new OrderPickupingProducer();
                pickupingProducer.Publish(new OrderPickupingMsg
                {
                    OrderType = OrderType.挂号订单,
                    OrderId = order.Id
                });

                return new CreateApptOrderResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    OrderId = order.Id,
                    OrderNo = order.OrderNo,
                    PayString = ""
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付中.ToInt32();
            //_ctx.SaveChanges();

            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                    {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付中.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            }

            // RMQ 16分钟后如果还是支付中则设置支付失败
            var payingTimeoutProducer = new OrderPayingTimeoutProducer();
            payingTimeoutProducer.Publish(new OrderPayingTimeoutMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = order.Id
            }, 16 * 60 * 1000);

            //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
            var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
            var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

            var payFee = (order.SumFee * 100).ToInt32().ToString();
            var superOpenIds = ConfigurationManager.AppSettings["OpenIdsForPayMin"]
                .Split(" , ", StringSplitOptions.RemoveEmptyEntries);
            if (superOpenIds.Contains(order.WxUserId.ToString()))
            {
                payFee = "1";
            }

            var result = WeixinPayV3Helper.ComposeJsApiParameter("就诊挂号", "AP" + order.OrderNo,
                payFee, GetClientIp(), payStartTime, payExpireTime, "Reg/PaySucceed", openid);


            return new CreateApptOrderResponse
            {
                ResultCode = result.ResultCode,
                ResultMsg = result.ResultMsg ?? "",
                PayString = result.Parameter ?? "",
                OrderId = order.Id,
                OrderNo = order.OrderNo,
            };
        }

        /// <summary>
        /// 生成直接挂号订单
        /// </summary>
        /// <returns></returns>
        /// <param name="cardId">就诊卡id</param>
        /// <param name="deptId">科室院内编号</param>
        /// <param name="deptName">科室名称</param>
        /// <param name="doctorId">医生院内编号</param>
        /// <param name="doctorName">医生名称</param>
        /// <param name="regDate">挂号日期</param>
        /// <param name="timeSlice">排班时段</param>
        /// <param name="startTime">分时开始时间</param>
        /// <param name="endTime">分时结束时间</param>
        /// <param name="regType">号源类型</param>
        /// <param name="fee"></param>
        /// <param name="treatFee"></param>
        /// <param name="otherFee"></param>
        /// <param name="sqno"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("CreateDirectOrder")]
        public CreateDirectOrderResponse CreateDirectOrder(int cardId, string deptId, string deptName,
            string doctorId, string doctorName, string regDate, string timeSlice, string startTime,
            string endTime, string regType,string fee, string treatFee, string otherFee,string sqno)
        {
            var azUser = AzUser.GetInApi(Request);
            Card card;
            ApptOrder order;
            string openid;
            using (var _ctx = new HzfyWeiXinEntities())
            {
                card = _ctx.HospCard.Where(x => x.Id == cardId && x.WxUserId == azUser.UserId)
                    .Select(x => new Card
                    {
                        CardNo = x.CardNo,
                        Birthdate = x.Birthdate,
                        CardType = x.CardType,
                        PatientName = x.PatientName
                    }).FirstOrDefault();
                if (card == null)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "找不到就诊卡信息"
                    };
                }


                if (System.DateTime.Now.Hour < 8)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "很抱歉，现在还不是挂号时间，请您于8点后再挂号！"
                    };
                }
                else if (System.DateTime.Now.Hour >= 12 &&
                         (String.Compare(DateTime.Now.ToString("HH:mm"), "14:30", StringComparison.Ordinal) < 0))
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "很抱歉，现在还不是挂号时间，请您于14点30分后再挂号！"
                    };
                }

                var sameOrder = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .FirstOrDefault(x =>
                        x.CardNo == card.CardNo
                        && x.RegDate == regDate
                        && x.DoctorId == doctorId
                        && x.TimeSlice == timeSlice);
                if (sameOrder != null)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "同个医生同个班次，只能挂号一次!"
                    };
                }

                var cardSameDayAppointMax = ConfigurationManager.AppSettings["CardSameDayAppointMax"].ToInt32();
                var cardApptCount = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .Count(x => x.CardNo == card.CardNo && x.RegDate == regDate);
                if (cardApptCount >= cardSameDayAppointMax)
                {
                    return new CreateDirectOrderResponse
                    {
                        ResultCode = "4",
                        ResultMsg = "同一天最多可以预约挂号" + cardSameDayAppointMax + "次!"
                    };
                }

                var userobj = _ctx.WxUser.FirstOrDefault(x => x.Id == azUser.UserId);
                openid = userobj == null ? "" : userobj.OpenId;

                var orderNo = GenerateNewOrderNo();

                //新建订单
                order = new ApptOrder
                {
                    WxUserId = azUser.UserId,
                    OrderType = ApptOrderExtensions.OrderType.预约.ToInt32().ToString(),
                    // 0-微信平台预约订单  1-其它平台预约订单 2-微信平台挂号订单
                    CardType = "0", //不分卡类型，由HIS识别
                    CardNo = card.CardNo,
                    DeptId = deptId,
                    DeptName = deptName,
                    DoctorId = doctorId,
                    DoctorName = doctorName,
                    OrderNo = orderNo,
                    RegDate = regDate,
                    OrderStatus = ApptOrderExtensions.OrderStatus.未锁号.ToInt32(), //新订单，未锁号（0）
                    TimeSlice = timeSlice,
                    StartTime = startTime,
                    EndTime = endTime,
                    RegType = regType,
                    PayState = ApptOrderExtensions.PayState.未付款.ToInt32().ToString(),
                    Fee = fee.ToDecimalOrDefault(),
                    TreatFee = treatFee.ToDecimalOrDefault(),
                    OtherFee = otherFee.ToDecimalOrDefault(),
                    SumFee = fee.ToDecimalOrDefault() + treatFee.ToDecimalOrDefault() + otherFee.ToDecimalOrDefault(),
                    CreateTime = DateTime.Now,
                    Sqno = sqno,
                    CardName = card.PatientName
                };

                _ctx.ApptOrder.Add(order);
                _ctx.SaveChanges();
            }


            //执行锁号操作
            var lockRequest = new Request4ExeLockSource();
            lockRequest.OrderId = order.OrderNo;
            lockRequest.DeptId = order.DeptId;
            lockRequest.DoctorId = order.DoctorId;
            lockRequest.RegDate = order.RegDate;
            lockRequest.TimeSlice = order.TimeSlice;
            lockRequest.RegType = order.RegType;
            lockRequest.StartTime = order.StartTime;
            lockRequest.EndTime = order.EndTime;
            lockRequest.RegFee = order.Fee.GetValueOrDefault().ToString();
            lockRequest.TreatFee = order.TreatFee.GetValueOrDefault().ToString();
            lockRequest.OtherFee = order.OtherFee.GetValueOrDefault().ToString();
            //lockRequest.SumFee = order.SumFee.GetValueOrDefault().ToString();
            //lockRequest.SqNo = order.Sqno;

            Response4ExeLockSource lockResponse;

            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisNewWs/ExeLockSource", lockRequest).Result;
                responseMsg.EnsureSuccessStatusCode();
                lockResponse = responseMsg.Content.ReadAsAsync<Response4ExeLockSource>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内锁号Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号失败.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }
                return new CreateDirectOrderResponse
                {
                    ResultCode = "7",
                    ResultMsg = "执行锁号操作超时"
                };
            }

            if (lockResponse.ResultCode != "0")
            {
                //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号失败.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para =
                        {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号失败.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
                }

                return new CreateDirectOrderResponse
                {
                    ResultCode = "8",
                    ResultMsg = lockResponse.ResultDesc
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.锁号成功.ToInt32();
            //order.LockTime = DateTime.Now;
            //_ctx.SaveChanges();
            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.锁号成功.ToInt32()),
                    new SqlParameter("@LockTime", DateTime.Now),
                    new SqlParameter("@OrderId", order.Id),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus,LockTime = @LockTime where Id=@OrderId", para);
            }

            //跳过预约，直接支付

            // 费用为0的直接设置为支付成功
            if (order.SumFee == 0)
            {
                //order.PayState = ApptOrderExtensions.PayState.已付款.ToInt32().ToString();
                //order.PayTime = DateTime.Now;
                //order.WxTransactionId = "0";
                //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付成功.ToInt32();
                //_ctx.SaveChanges();
                using (var _ctx = new HzfyWeiXinEntities())
                {
                    SqlParameter[] para = new SqlParameter[]
                    {
                        new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付成功.ToInt32()),
                        new SqlParameter("@WxTransactionId", "0"),
                        new SqlParameter("@PayTime", DateTime.Now),
                        new SqlParameter("@PayState", ApptOrderExtensions.PayState.已付款.ToInt32().ToString()),
                        new SqlParameter("@OrderId", order.Id)
                    };
                    _ctx.Database.ExecuteSqlCommand(
                        "Update ApptOrder set OrderStatus= @OrderStatus,PayTime = @PayTime,PayState=@PayState, " +
                        "WxTransactionId=@WxTransactionId where Id=@OrderId", para);
                }

                // RMQ 执行取号
                var pickupingProducer = new OrderPickupingProducer();
                pickupingProducer.Publish(new OrderPickupingMsg
                {
                    OrderType = OrderType.挂号订单,
                    OrderId = order.Id
                });

                return new CreateDirectOrderResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    OrderId = order.Id,
                    OrderNo = order.OrderNo,
                    PayString = ""
                };
            }

            //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付中.ToInt32();
            //_ctx.SaveChanges();
            using (var _ctx = new HzfyWeiXinEntities())
            {
                SqlParameter[] para =
                    {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付中.ToInt32()),
                    new SqlParameter("@OrderId", order.Id),
                     };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);
            }

            // RMQ 16分钟后如果还是支付中则设置支付失败
            var payingTimeoutProducer = new OrderPayingTimeoutProducer();
            payingTimeoutProducer.Publish(new OrderPayingTimeoutMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = order.Id
            }, 16 * 60 * 1000);

            //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
            var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
            var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

            var payFee = (order.SumFee * 100).ToInt32().ToString();
            var superOpenIds = ConfigurationManager.AppSettings["OpenIdsForPayMin"]
                .Split(" , ", StringSplitOptions.RemoveEmptyEntries);
            if (superOpenIds.Contains(order.WxUserId.ToString()))
            {
                payFee = "1";
            }


            var result = WeixinPayV3Helper.ComposeJsApiParameter("就诊挂号", "AP" + order.OrderNo,
              payFee, GetClientIp(), payStartTime, payExpireTime, "Reg/PaySucceed", openid);

            return new CreateDirectOrderResponse
            {
                ResultCode = result.ResultCode,
                ResultMsg = result.ResultMsg ?? "",
                PayString = result.Parameter ?? "",
                OrderId = order.Id,
                OrderNo = order.OrderNo,

            };
        }


        /// <summary>
        /// 用户取消支付
        /// </summary>
        /// <param name="orderId">订单id</param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("PayFailed")]
        public PayFailedResponse PayFailed(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            string orderType;
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.支付中)
                    .Where(x => x.WxUserId == azUser.UserId && x.Id == orderId).Select(x => new
                    {
                        x.OrderType
                    }).FirstOrDefault();
                if (order == null)
                {
                    return new PayFailedResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "订单不存在"
                    };
                }
                orderType = order.OrderType;

                //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付失败.ToInt32();
                //_ctx.SaveChanges();

                SqlParameter[] para =
                {
                    new SqlParameter("@OrderStatus", ApptOrderExtensions.OrderStatus.支付失败.ToInt32()),
                    new SqlParameter("@OrderId", orderId),
                };
                _ctx.Database.ExecuteSqlCommand(
                    "Update ApptOrder set OrderStatus= @OrderStatus where Id=@OrderId", para);

            }

            if (orderType == ApptOrderExtensions.OrderType.预约.ToInt32().ToString())
            {
                //// RMQ 执行取消预约操作
                //var unapptingProducer = new OrderUnapptingProducer();
                //unapptingProducer.Publish(new OrderUnapptingMsg
                //{
                //    OrderType = Rmq.Center.OrderType.挂号订单,
                //    OrderId = orderId
                //});

                // RMQ 执行取消锁号操作
                var unlockingProducer = new OrderUnlockingProducer();
                unlockingProducer.Publish(new OrderUnlockingMsg
                {
                    OrderType = OrderType.挂号订单,
                    OrderId = orderId
                });
            }

            return new PayFailedResponse
            {
                ResultCode = "0",
                ResultMsg = ""
            };
        }


        /// <summary>
        /// 获取挂号状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetRegStatus")]
        public GetRegStatusResponse GetRegStatus(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.Where(x => x.Id == orderId && x.WxUserId == azUser.UserId)
                   .Select(x => new
                    {
                        x.OrderStatus
                    }).FirstOrDefault(); ;
                if (order == null)
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "订单不存在"
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.取号中.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.支付中.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.支付成功.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "2",
                        FailedMsg = ""
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.取号成功.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "0",
                        FailedMsg = ""
                    };
                }

                return new GetRegStatusResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    RegStatus = "1",
                    FailedMsg = ""
                };
            }
        }

        /// <summary>
        /// 退号操作
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("Unpickup")]
        public UnpickupResponse Unpickup(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.IsStatus(ApptOrderExtensions.OrderStatus.取号成功)
                    .Where(x => x.WxUserId == azUser.UserId
                                         && x.Id == orderId).Select(x => new
                                         {
                                             x.RegDate,
                                             x.OrderType
                                         }).FirstOrDefault(); ;
                if (order == null || order.OrderType != ApptOrderExtensions.OrderType.预约.ToInt32().ToString())
                {
                    return new UnpickupResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "找不到订单"
                    };
                }

                if (string.CompareOrdinal(order.RegDate ?? "", DateTime.Today.ToString("yyyy-MM-dd")) <= 0)
                {
                    return new UnpickupResponse
                    {
                        ResultCode = "2",
                        ResultMsg = "退预约号必须在就诊前一天16:00之前"
                    };
                }
            }

            // RMQ 执行退号
            var unpickupProducer = new OrderUnpickupingProducer();
            unpickupProducer.Publish(new OrderUnpickupingMsg
            {
                OrderType = OrderType.挂号订单,
                OrderId = orderId,
                Reason = 1,
            });

            return new UnpickupResponse
            {
                ResultCode = "0",
                ResultMsg = ""
            };
        }

        /// <summary>
        /// 生成挂号订单号
        /// </summary>
        /// <returns></returns>
        public string GenerateNewOrderNo()
        {
            var orderNo = "WX" + DateTime.Now.Date.ToString("yyyyMMdd");
            lock (OrderNoLocker)
            {
                orderNo += (DateTime.Now - DateTime.Now.Date).TotalMilliseconds.ToString("00000000");
                Thread.Sleep(1);
            }

            return orderNo;
        }

        public string GetClientIp()
        {
            if (Request.Properties.ContainsKey("MS_HttpContext"))
            {
                string ip = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                //判断是否有代理服务器
                if (string.IsNullOrEmpty(ip))
                {
                    //没有代理服务器,如果有代理服务器获取的是代理服务器的IP
                    ip = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                }

                string pattrn = @"(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])";
                if (!string.IsNullOrEmpty(ip) && System.Text.RegularExpressions.Regex.IsMatch(ip, pattrn))
                {
                    return ip;
                }

                return "127.0.0.1";
            }
            else
            {
                return "127.0.0.1";
            }
        }


        /// <summary>
        /// 微信支付通知回调
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [ActionName("PaySucceed")]
        public HttpResponseMessage PaySucceed()
        {
            
            var result = WeixinPayV3Helper.ParsePayNotify(Request.RequestUri, Request.Content.ReadAsStringAsync().Result.Copy());
            if (result.ResultCode != "0")
            {
                #region 记录验证失败的支付通知

                using (var _ctx = new HzfyWeiXinEntities())
                {
                    var wxPayNotifyLog = new WxPayNotifyLog();
                    wxPayNotifyLog.Uri = Request.RequestUri.AbsoluteUri;
                    wxPayNotifyLog.IsVerified = 2;
                    wxPayNotifyLog.RecCreateDt = DateTime.Now;
                    _ctx.WxPayNotifyLog.Add(wxPayNotifyLog);
                    _ctx.SaveChanges();
                }

                #endregion
                return new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    Content = new StringContent(result.FailResponse)
                };
            }
            var transactionId = result.PayOrder.TransactionId;
     
            lock (PayNotifyLocker)
            {
                try
                {
                    OrderBase order = null;
                    using (var _ctx = new HzfyWeiXinEntities())
                    {
                        if (
                            _ctx.WxPayNotifyLog.Any(
                                x => x.TransactionId == transactionId && x.TradeState == 0 && x.IsVerified == 1))
                        {
                            return new HttpResponseMessage
                            {
                                StatusCode = HttpStatusCode.OK,
                                Content = new StringContent(result.SuccessResponse)
                            };
                        }
                        if (result.ResultCode == "0") //成功
                        {

                            if (result.PayOrder.TradeState == "0")
                            {
                                //处理订单 并记录日志
                                if (result.PayOrder.OutTradeNo.StartsWith("AP"))
                                {
                                    var orderNo = result.PayOrder.OutTradeNo.Substring(2);
                                    order = _ctx.ApptOrder.Where(x => x.OrderNo == orderNo).Select(x => new OrderBase
                                    {
                                        OrderStatus = x.OrderStatus,
                                        Id = x.Id,
                                        SumFee = x.SumFee
                                    }).FirstOrDefault();
                                    ;
                                }
                            }
                        }
                    }
                    if (order != null)
                    {
                        if (order.OrderStatus == ApptOrderExtensions.OrderStatus.支付中.ToInt32())
                        {
                            //order.PayState = ApptOrderExtensions.PayState.已付款.ToInt32().ToString();
                            //order.PayTime = DateTime.ParseExact(result.PayOrder.TimeEnd,
                            //    "yyyyMMddHHmmss",
                            //    CultureInfo.CurrentCulture);
                            //order.WxTransactionId = transactionId;
                            //order.OrderStatus = ApptOrderExtensions.OrderStatus.支付成功.ToInt32();
                            //_ctx.SaveChanges();
                            using (var _ctx = new HzfyWeiXinEntities())
                            {
                                var para = new SqlParameter[]
                                {
                                    new SqlParameter("@OrderStatus",
                                        ApptOrderExtensions.OrderStatus.支付成功.ToInt32()),
                                    new SqlParameter("@WxTransactionId", transactionId),
                                    new SqlParameter("@PayTime",
                                        DateTime.ParseExact(result.PayOrder.TimeEnd, "yyyyMMddHHmmss",
                                            CultureInfo.CurrentCulture)),
                                    new SqlParameter("@PayState",
                                        ApptOrderExtensions.PayState.已付款.ToInt32().ToString()),
                                    new SqlParameter("@OrderId", order.Id)
                                };
                                _ctx.Database.ExecuteSqlCommand(
                                    "Update ApptOrder set OrderStatus= @OrderStatus,PayTime = @PayTime,PayState=@PayState, " +
                                    "WxTransactionId=@WxTransactionId where Id=@OrderId", para);
                            }

                            // RMQ 执行取号操作
                            var pickupingProducer = new OrderPickupingProducer();
                            pickupingProducer.Publish(new OrderPickupingMsg
                            {
                                OrderType = Rmq.Center.OrderType.挂号订单,
                                OrderId = order.Id
                            });
                        }
                        else if (order.OrderStatus == ApptOrderExtensions.OrderStatus.取消预约成功.ToInt32() ||
                                 order.OrderStatus == ApptOrderExtensions.OrderStatus.支付失败.ToInt32())
                        {
                            //如果订单状态为取消预约成功、支付失败
                            // RMQ 执行退费操作
                            if (order.SumFee > 0)
                            {
                                var refundingProducer = new OrderRefundingPickupFailedProducer();
                                refundingProducer.Publish(new OrderRefundingPickupFailedMsg
                                {
                                    OrderType = OrderType.挂号订单,
                                    OrderId = order.Id
                                });
                            }
                        }

                    }

                    using (var _ctx = new HzfyWeiXinEntities())
                    {
                        //记录通知日志
                        var orderNotifyLog = new WxPayNotifyLog
                        {
                            ServiceVersion = result.PayOrder.ServiceVersion,
                            Attach = result.PayOrder.Attach,
                            BankBillNo = result.PayOrder.BankBillNo,
                            BankType = result.PayOrder.BankType,
                            BuyerAlias = result.PayOrder.BuyerAlias,
                            Discount = result.PayOrder.Discount.ToNullableInt32(),
                            //FeeType = result.PayOrder.FeeType.ToNullableInt32(),
                            InputCharset = result.PayOrder.InputCharset,
                            NotifyId = result.PayOrder.NotifyId,
                            SignType = result.PayOrder.SignType,
                            Sign = result.PayOrder.Sign,
                            SignKeyIndex = result.PayOrder.SignKeyIndex.ToNullableInt32(),
                            //TradeMode = result.PayOrder.TradeMode.ToNullableInt32(),
                            TradeState = result.PayOrder.TradeState.ToNullableInt32(),
                            PayInfo = result.PayOrder.PayInfo,
                            Partner = result.PayOrder.Partner,
                            TotalFee = result.PayOrder.TotalFee.ToNullableInt32(),
                            TransactionId = result.PayOrder.TransactionId,
                            OutTradeNo = result.PayOrder.OutTradeNo,
                            TimerEnd = result.PayOrder.TimeEnd,
                            TransportFee = result.PayOrder.TransportFee.ToNullableInt32(),
                            ProductFee = result.PayOrder.ProductFee.ToNullableInt32(),
                            PostAppId = result.PayUser.AppId,
                            PostTimeStamp = result.PayUser.TimeStamp,
                            PostNonceStr = result.PayUser.NonceStr,
                            PostOpenId = result.PayUser.OpenId,
                            PostAppSignature = result.PayUser.AppSignature,
                            PostIsSubscribe = result.PayUser.IsSubscribe,
                            Uri = Request.RequestUri.AbsoluteUri,
                            IsVerified = 1,
                            RecCreateDt = DateTime.Now
                        };


                        _ctx.WxPayNotifyLog.Add(orderNotifyLog);
                        _ctx.SaveChanges();
                    }

                    return new HttpResponseMessage
                    {
                        StatusCode = HttpStatusCode.OK,
                        Content = new StringContent(result.SuccessResponse)
                    };
                }
                catch (System.Data.SqlClient.SqlException sqlEx)
                {
                    Logger.ErrorFormat("Reg PaySuccessed SqlException Error:{0}", JsonConvert.SerializeObject(sqlEx));
                }
                catch (Exception e)
                {
                    Logger.ErrorFormat("Reg PaySuccessed Error:{0}", JsonConvert.SerializeObject(e));

                }
            }

            #region 记录验证失败的支付通知

            using (var _ctx = new HzfyWeiXinEntities())
            {
                var unverifiedNotifyLog = new WxPayNotifyLog();
                unverifiedNotifyLog.Uri = Request.RequestUri.AbsoluteUri;
                unverifiedNotifyLog.IsVerified = 0;
                unverifiedNotifyLog.RecCreateDt = DateTime.Now;
                _ctx.WxPayNotifyLog.Add(unverifiedNotifyLog);
                _ctx.SaveChanges();
            }

            #endregion

            return new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent(result.FailResponse)
            };


        }


        /// <summary>
        /// 获取取消挂号状态
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        [HttpGet]
        [ActionName("GetCancellRegStatus")]
        public GetRegStatusResponse GetCancellRegStatus(int orderId)
        {
            var azUser = AzUser.GetInApi(Request);
            using (var _ctx = new HzfyWeiXinEntities())
            {
                var order = _ctx.ApptOrder.FirstOrDefault(x => x.Id == orderId && x.WxUserId == azUser.UserId);
                if (order == null)
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "1",
                        ResultMsg = "订单不存在"
                    };
                }

                //对于订单金额为0的挂号单，微信退号中就算成功,不做微信退款操作
                if (order.SumFee == 0 && order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号中.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "0",
                        FailedMsg = ""
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号中.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号成功.ToInt32()
                    || order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号退款中.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "2",
                        FailedMsg = ""
                    };
                }

                if (order.OrderStatus == ApptOrderExtensions.OrderStatus.微信退号退款成功.ToInt32())
                {
                    return new GetRegStatusResponse
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        RegStatus = "0",
                        FailedMsg = ""
                    };
                }

                return new GetRegStatusResponse
                {
                    ResultCode = "0",
                    ResultMsg = "",
                    RegStatus = "1",
                    FailedMsg = ""
                };
            }
        }

        /// <summary>
        /// 手工退费
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [ActionName("test")]
        [AllowAnonymous]
        public GetRegFeeResponse test()
        {
            var a = WeixinPayV3Helper.DoRefund("BLWX2017061552885081", "4004772001201706155829092454", "BLWX2017061552885081", 4951, 4951);
            return new GetRegFeeResponse
            {
                ResultCode = "0",
                ResultMsg = "",

            };
        }

        //[AllowAnonymous]
        //[HttpGet]
        //[ActionName("TestDoRefund")]
        //public CreateDirectOrderResponse TestDoRefund()
        //{
        //    string outno = "APWX2016061420513411";
        //    int fee = 700;
        //    var result = WeixinPayV3Helper.DoRefund(outno, "4009282001201606147229458705", outno, fee, fee);
        //    return new CreateDirectOrderResponse
        //    {
        //        ResultCode = "1",
        //        ResultMsg = ""
        //    };
        //}


        //[AllowAnonymous]
        //[HttpGet]
        //[ActionName("Pay")]
        //public CreateDirectOrderResponse Pay()
        //{

        //    //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
        //    var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
        //    var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

        //    var payFee = (1 * 100).ToInt32().ToString();



        //    var result = WeixinPayV3Helper.ComposeJsApiParameter("就诊挂号", "AP3" ,
        //      payFee, GetClientIp(), payStartTime, payExpireTime, "Reg/PaySucceed", "");

        //    return new CreateDirectOrderResponse
        //    {
        //        ResultCode = "6",
        //        ResultMsg = ""
        //    };
        //}

    }

}

 
